#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <algorithm>
#include <iomanip>
#include <set>
using namespace std;

#include <ext/hash_set>
#include <ext/hash_map>
#include <ext/hash_fun.h>
using namespace __gnu_cxx;

#include "pin.H"

//-- Function Prototypes -----------------------------------------------------//

VOID Image_Callback(IMG img, VOID *v);
VOID Fini(INT32 code, VOID *v);

//-- Main --------------------------------------------------------------------//

int main(int argc, char * argv[])
{
    PIN_Init(argc, argv);

    PIN_InitSymbols();

    IMG_AddInstrumentFunction(Image_Callback, 0);
    PIN_AddFiniFunction(Fini, 0);

    // TODO: Perform any init work here (such as opening the output file).

    PIN_StartProgram(); 

    return 0;
}

//-- Instrumentation ---------------------------------------------------------//

// TODO: Define your instrumentation routines here.

//-- Pin Callbacks -----------------------------------------------------------//

/* An image callback.  This callback will be called for each image in the 
 * target application when it gets loaded into memory.  "images" consist of the
 * main application binary, and any shared libraries loaded at runtime.
 */
VOID Image_Callback(IMG img, VOID *v)
{
    // Search for a "malloc" routine in this image.
    RTN rtn = RTN_FindByName(img, "malloc");
    if (RTN_Valid(rtn))
    {
        RTN_Open(rtn);

        // TODO: Instrument the entry and exit points of malloc to obtain memory 
        //       allocation size requests, and the pointers returned by malloc.  

        RTN_Close(rtn);
    }
    
    // Search for a "free" routine in this image.
    rtn = RTN_FindByName(img, "free");
    if (RTN_Valid(rtn))
    {
        RTN_Open(rtn);

        // TODO: Instrument entry point of free to obtain free addresses.

        RTN_Close(rtn); }

    // You can ignore realloc. 
    // Note that some of the addresses passed to your "free instrumentation" may
    // be invalid because of this simplification.  You should ignore them.) 
}

// This function is called when the application exits
VOID Fini(INT32 code, VOID *v)
{
    // TODO: Print out your trace file here (to a file called trace-out.rep)
  
    // You may also write to the file in your instrumentation routines, but you
    // should write out all non-freed allocations here, to make your trace
    // "balanced".
}

